<template>
	<view class="e-switch" :class="[ns.is('disabled',elDisabled)]" :style="[switchStyle, addStyle(props.customStyle)]"
		@tap="clickHandler">
		<view class="e-switch__slot" :style="[slotStyle]">
			<slot>
			</slot>
		</view>
		<view class="e-switch__bg" :style="[bgStyle]">
		</view>
		<view class="e-switch__node" :class="[props.modelValue ? 'e-switch__node--on':'e-switch__node--off']"
			:style="[nodeStyle]" ref="e-switch__node">
			<e-loading-icon :show="props.loading" mode="circle" timingFunction='linear'
				:color="props.modelValue ? props.activeColor : '#AAABAD'" :size="Number(props.size) * 0.6" />
		</view>
	</view>
</template>
<script lang="ts">
	import {defineComponent} from 'vue'
	import mpMixin from '../../libs/mixin/mpMixin'
	/**
	 * switch 开关选择器
	 * @description 选择开关一般用于只有两个选择，且只能选其一的场景。
	 * @tutorial https://www.uviewui.com/components/switch.html
	 * @property {Boolean}						loading			是否处于加载中（默认 false ）
	 * @property {Boolean}						disabled		是否禁用（默认 false ）
	 * @property {String | Number}				size			开关尺寸，单位px （默认 25 ）
	 * @property {String}						activeColor		打开时的背景色 （默认 '#2979ff' ）
	 * @property {String} 						inactiveColor	关闭时的背景色 （默认 '#ffffff' ）
	 * @property {Boolean | String | Number}	value			通过v-model双向绑定的值 （默认 false ）
	 * @property {Boolean | String | Number}	activeValue		打开选择器时通过change事件发出的值 （默认 true ）
	 * @property {Boolean | String | Number}	inactiveValue	关闭选择器时通过change事件发出的值 （默认 false ）
	 * @property {Boolean}						asyncChange		是否开启异步变更，开启后需要手动控制输入值 （默认 false ）
	 * @property {String | Number}				space			圆点与外边框的距离 （默认 0 ）
	 * @property {Object}						customStyle		定义需要用到的外部样式
	 *
	 * @event {Function} change 在switch打开或关闭时触发
	 * @example <e-switch v-model="checked" active-color="red" inactive-color="#eee"></e-switch>
	 */
	export default defineComponent({
		name: "e-switch",
		mixins: [mpMixin]
	});
</script>
<script lang="ts" setup>
	import {
		watch,
		computed,
		nextTick,
		toRefs
	} from 'vue'
	import {
		switchProps,
		switchEmits
	} from './props';
	import {
		addUnit,
		addStyle,
		throwError
	} from '../../libs/utils/_utils'
	import {
		useNamespace,
		useDisabled,
		useDefaultProps
	} from '../../libs/hooks'
	import type {
		StyleProperties
	} from "../../libs/tokens";
	import componentsProps, {
		type DefaultProps
	} from "../../libs/config/componentsProps";

	const {
		switch: switchDefaultProps
	} = toRefs(componentsProps);

	const _props = defineProps(switchProps)

	const props = useDefaultProps < DefaultProps['switch'] > (_props, switchDefaultProps);
	const emit = defineEmits(switchEmits)

	const ns = useNamespace('switch')

	watch(() => props.value.modelValue, (n) => {
		if (n !== props.value.inactiveValue && n !== props.value.activeValue) {
			throwError('e-switch', 'v-model绑定的值必须为inactiveValue、activeValue二者之一')
		}
	}, {
		immediate: true
	})
	const elDisabled = useDisabled()
	const isActive = computed(() => {
		return props.value.modelValue === props.value.activeValue;
	})
	const customInactiveColor = computed(() => {
		// 之所以需要判断是否自定义了“非激活”颜色，是为了让node圆点离外边框更宽一点的距离
		return props.value.inactiveColor !== '#fff' && props.value.inactiveColor !== '#ffffff'
	})
	const switchStyle = computed(() => {
		let style: StyleProperties = {}
		// 这里需要加2，是为了腾出边框的距离，否则圆点node会和外边框紧贴在一起
		style.width = addUnit((props.value.size as number) * 2 + 2)
		style.height = addUnit(Number((props.value.size as number)) + 2)
		// style.borderColor = this.value ? 'rgba(0, 0, 0, 0)' : 'rgba(0, 0, 0, 0.12)'
		// 如果自定义了“非激活”演示，name边框颜色设置为透明(跟非激活颜色一致)
		// 这里不能简单的设置为非激活的颜色，否则打开状态时，会有边框，所以需要透明
		if (customInactiveColor.value) {
			style.borderColor = 'rgba(0, 0, 0, 0)'
		}
		style.backgroundColor = isActive.value ? props.value.activeColor : props.value.inactiveColor
		return style;
	})
	const slotStyle = computed(() => {
		let style: StyleProperties = {}
		if (isActive.value) {
			style.paddingRight = addUnit((props.value.size as number) - (props.value.space as number))
		} else {
			style.paddingLeft = addUnit((props.value.size as number) - (props.value.space as number))
		}
		return style
	})
	const nodeStyle = computed(() => {
		let style: StyleProperties = {}
		// 如果自定义非激活颜色，将node圆点的尺寸减少两个像素，让其与外边框距离更大一点
		style.width = addUnit((props.value.size as number) - (props.value.space as number))
		style.height = addUnit((props.value.size as number) - (props.value.space as number))
		const translateX = isActive.value ? addUnit(props.value.space) : addUnit((props.value.size as number));
		style.transform = `translateX(-${translateX})`
		return style
	})
	const bgStyle = computed(() => {
		let style: StyleProperties = {}
		// 这里配置一个多余的元素在HTML中，是为了让switch切换时，有更良好的背景色扩充体验(见实际效果)
		style.width = addUnit(Number((props.value.size as number)) * 2 - (props.value.size as number) / 2)
		style.height = addUnit((props.value.size as number))
		style.backgroundColor = props.value.inactiveColor
		// 打开时，让此元素收缩，否则反之
		style.transform = `scale(${isActive.value ? 0 : 1 })`
		return style
	})

	const clickHandler = () => {
		if (!elDisabled.value && !props.value.loading) {
			const oldValue = isActive.value ? props.value.inactiveValue : props.value.activeValue
			if (!props.value.asyncChange) {
				emit('input', oldValue as boolean)
				emit("update:modelValue", oldValue as boolean);
			}
			// 放到下一个生命周期，因为双向绑定的value修改父组件状态需要时间，且是异步的
			nextTick(() => {
				emit('change', oldValue as boolean)
			})
		}
	}
</script>

<style lang="scss" scoped>
	@import "../../libs/theme/switch.scss";
</style>
